package cn.dansj.controller;

import cn.dansj.common.request.annotation.http.GetMethod;
import cn.dansj.common.request.annotation.http.PostMethod;
import cn.dansj.common.request.annotation.http.RequestMappingMethod;
import cn.dansj.common.request.annotation.http.RequestParam;
import cn.dansj.bean.ArticleTitle;
import cn.dansj.common.utils.bean.Return;
import cn.dansj.common.utils.json.DictMap;
import cn.dansj.entity.Article;
import cn.dansj.entity.ArticleTag;
import cn.dansj.entity.Setting;
import cn.dansj.common.utils.enums.BooleanType;
import cn.dansj.service.ArticleService;
import cn.dansj.service.ArticleTagService;
import cn.dansj.service.SettingService;
import cn.dansj.common.request.RequestUtils;
import cn.dansj.common.redis.RedisUtils;
import cn.dansj.common.utils.transfer.GetTime;
import cn.dansj.common.utils.transfer.Transformation;
import cn.dansj.common.utils.transfer.RandomUtils;
import cn.dansj.common.utils.transfer.Verification;
import cn.dansj.utils.project.ProjectUtils;
import com.alibaba.fastjson2.JSONObject;
import org.springframework.data.domain.Page;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@RequestMappingMethod("/article")
public class ArticleController {
    private final ArticleService articleService;
    private final RedisUtils redisUtils;
    private final SettingService settingService;
    private final ArticleTagService articleTagService;

    public ArticleController(ArticleService articleService, RedisUtils redisUtils, SettingService settingService, ArticleTagService articleTagService) {
        this.articleService = articleService;
        this.redisUtils = redisUtils;
        this.settingService = settingService;
        this.articleTagService = articleTagService;
    }

    @GetMethod(value = "/list")
    public Return<?> getArticles(@RequestParam("search") JSONObject search, @RequestParam int page, @RequestParam int limit) {
        String title = search.getString("title");
        String type = search.getString("type");
        int status = Integer.parseInt(Transformation.nvl(search.getString("status"), "-1"));
        Page<Article> articles = articleService.search(page, limit, title, type, status);
        final List<Map<String, Object>> result = articles.getContent().stream().map(e -> DictMap.of("sequence", e.getSequence(), "title", e.getTitle(), "source", e.getSourceType(),
                "status", e.getStatus(), "type", e.getType(), "crtTime", e.getCrtTime(), "updateTime", e.getUpdateTime())).collect(Collectors.toList());
        return Return.T(result).setTotalRecord(articles.getTotalElements());
    }

    @PostMethod("/save")
    public Return<?> saveArticle(@RequestParam Article article) {
        Timestamp now = GetTime.dbTimestamp();
        if (!Transformation.castToBoolean(article.getSequence())) {
            article.setSequence(RandomUtils.getUid());
            article.setCrtTime(now);
        }
        article.setUpdateTime(now);

        String content = article.getContent();
        // 图片后面的#（标题）:（高亮）添加换行，不然格式有问题
        Pattern pattern = Pattern.compile("!\\[]\\((.*?)\\)[#:`>]");
        Matcher matcher = pattern.matcher(content); // 创建Matcher对象

        while (matcher.find()) {
            content = content.replace(matcher.group(), new StringBuilder(matcher.group()).insert(matcher.group().length() - 1, "\n").toString());
        }
        article.setContent(content);

        redisUtils.delete("article@" + article.getSequence());

        if (article.getStatus() == 1) {
            redisUtils.hmset("article@" + article.getSequence(), article.toJSONObject());
        }

        articleTagService.deleteByBlogSequence(article.getSequence());

        final List<String> settings = settingService.getAllByClassCode("blog.tag").stream().map(Setting::getValue).collect(Collectors.toList());
        int increase = 1;
        List<Setting> newSettings = new ArrayList<>();
        List<ArticleTag> tags = new ArrayList<>();
        for (String tag : article.getTag().split(",")) {
            final ArticleTag articleTag = new ArticleTag();
            articleTag.setSequence(RandomUtils.sequence());
            articleTag.setBlogSequence(article.getSequence());
            articleTag.setTag(tag);
            tags.add(articleTag);

            if (Verification.checkNotNull(tag) && !settings.contains(tag)) {
                int index = settings.size() + increase;
                final Setting setting = new Setting();
                setting.setClassCode("blog.tag");
                setting.setSequence(RandomUtils.sequence());
                setting.setName("tag_" + index);
                setting.setValueType(1);
                setting.setValue(tag);
                setting.setRn(index);
                newSettings.add(setting);
                increase += 1;
            }
        }
        settingService.save(newSettings);
        if (article.getStatus() == 1) articleTagService.save(tags);
        redisUtils.delete("system.setting@blog.tag");
        return Return.T(articleService.save(article));
    }

    @GetMethod("/cache")
    public Return<?> cache() {
        redisUtils.deleteByPrefix("article@*");
        final List<Article> articles = articleService.getList();
        for (Article article : articles) {
            redisUtils.hmset("article@" + article.getSequence(), article.toJSONObject());
        }
        return Return.T(articles.size());
    }

    @GetMethod("/detail")
    public Return<?> detail(@RequestParam String sequence) {
        final Article detail = articleService.detail(sequence);
        return Return.T(detail).setStatus(detail != null).setMessage(detail == null ? "该文章已不存在" : "");
    }

    @PostMethod("/delete")
    public Return<?> delete(@RequestParam String sequence) {
        redisUtils.delete("article@" + sequence);
        return Return.T(articleService.delete(sequence));
    }

    @GetMethod("/getList")
    public Return<?> getList(@RequestParam(required = false) String category,
                             @RequestParam(required = false) String tag,
                             @RequestParam(required = false, defaultValue = "1") int page,
                             @RequestParam(required = false, defaultValue = "5") int limit) {
        final Page<Article> list = articleService.getList(category, tag, page, limit);
        final List<ArticleTitle> data = list.getContent().stream().map(e -> DictMap.parseObject(e, ArticleTitle.class)).collect(Collectors.toList());
        return Return.T(data).setTotalRecord(list.getTotalElements());
    }

    @GetMethod(value = "/show", encrypt = BooleanType.TRUE)
    public Return<?> show(@RequestParam String sequence) {
        JSONObject article = DictMap.from(redisUtils.hgetall("article@" + sequence));
        if (Verification.checkNull(article)) {
            return RequestUtils.response404();
        }
        return Return.T(DictMap.parseObject(article, Article.class));
    }

    @GetMethod("/type")
    public Return<?> type() {
        JSONObject setting = ProjectUtils.getSettingByRedis("blog.type");
        setting.remove("cacheDate");
        return Return.T(setting.values());
    }

    @GetMethod("/tag")
    public Return<?> tag() {
        JSONObject setting = ProjectUtils.getSettingByRedis("blog.tag");
        setting.remove("cacheDate");
        return Return.T(setting.values());
    }

    @GetMethod("/category")
    public Return<?> category() {
        return Return.T(articleService.category().stream().map(e -> DictMap.of("name", e[0], "num", e[1])).collect(Collectors.toList()));
    }

    @GetMethod("/tagCount")
    public Return<?> tagCount() {
        return Return.T(articleTagService.tagCount().stream().map(e -> DictMap.of("name", e[0], "num", e[1])).collect(Collectors.toList()));
    }

    @GetMethod("/search")
    public Return<?> searchArticle(@RequestParam String keyword) {
        return Return.T(articleService.search(keyword));
    }
}
